feat: uninstall installed plugins (#37) - #228
Merged
Merged
Conversation
Add `!plugin uninstall <name>`, the inverse of `!plugin install` (#36): it removes the plugin from the persistent manifest and deletes its staged copy, so it no longer auto-loads at start-up. It is orthogonal to `!plugin unload` — it does NOT stop a running instance (a plugin already loaded this session stays active until `!plugin unload` or restart); the single "uninstalled" log reflects only the change to the persistent set. The engine grows `PluginEngineCommand::UninstallPlugin`: it normalizes the name (`foo`/`foo.lua` both work), errors if the plugin isn't installed, updates the manifest, then deletes the staged `<name>.lua`. It never deletes a bundled STDLIB file (`scope.lua`/`shell.lua`): install rejects reserved names, so such an entry can only come from a hand-edited manifest, and silently losing a user-customized `scope.lua` to it would be a nasty surprise — the manifest entry is still cleaned. `Installed` gains `remove`; the `!plugin` command handler gains the `uninstall` subcommand. Tests: a manifest `remove` unit test; e2e for uninstall (manifest entry + staged file gone), uninstalling something not installed (error), and the stdlib-safety guard (a corrupt manifest listing `scope` cleans the entry but keeps scope.lua). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Closes #37. Adds
!plugin uninstall <name>, the inverse of!plugin install(#36): it removes the plugin from the persistent manifest and deletes its staged copy, so it no longer auto-loads at start-up.!plugin listshows the remaining set.It is orthogonal to
!plugin unload: uninstall changes only the persistent set — a plugin already loaded this session stays active until you!plugin unloadit or restart. (Decided with the issue author.)How
src/plugin/engine.rs—PluginEngineCommand::UninstallPlugin. The handler normalizes the name (foo/foo.luaboth work viaget_plugin_name), errors if the plugin isn't installed, updates the manifest, then deletes the staged<name>.lua. A missing file is tolerated; other IO errors warn but don't abort (the manifest, which drives auto-load, is already updated).STDLIBfile (scope.lua/shell.lua).!plugin installrejects reserved names, so a manifest listing one can only come from a hand-edited file; silently losing a user-customizedscope.luato it would be a nasty surprise, so the file is preserved (the bogus manifest entry is still cleaned). This closed the one defense-in-depth gap flagged by an adversarial review of the diff.src/plugin/installed.rs—Installed::remove(returns whether it was present).src/inputs/inputs_task.rs— the!pluginhandler gains theuninstallsubcommand (arg-required), alongside the existing load/reload/install/list/unload.plugins/README.md.Tests
installed.rsunit test forremove(presence reporting + dedup-safety).tests/tui_e2e.rs:scopehas the entry cleaned butscope.luasurvives.All 232 unit + 23 e2e tests pass (1 e2e ignored on macOS per the existing PTY-baud limitation); tree is warning-clean under
#![deny(warnings)].🤖 Generated with Claude Code